<?php
class module extends bot_base {
	public  $autoparse = true;
	private $cmds = array();
	private $handlers = array();
	private $bot;
	protected $help = 'help';
	protected $gen_help = array();
	
	public function __construct($name, &$bot) {
		$this->exec_module = $name;	
		$this->bot = $bot;
	}
	private function send($msg) {
		$this->bot->send(trim($msg), $this->data_temp);
	}
	public function getHelp($admin = false) {
		$a = array();
		foreach ($this->cmds as $k=>$v) {
			if ($admin & $this->handlers[$k]['admin'])
				$a[] = $v[$k]['cmd'];
		}
		return $a;
	}
	public function addCommand($cmd, $desc, $val_ereg=null, $admin=false) {
		//nowy handler
		$handler = count($this->handlers);
		//tworzymy val_ereg ktory pokaze sie w pomocy
		$help = ((isset($val_ereg)&& $val_ereg!=='.+' && $val_ereg !== '.*')?' '.$val_ereg:'');
		//Jezeli jest jakis var_ereg to musi on byc ciagly
		if ($val_ereg !== null) $val_ereg = '^'.$val_ereg.'$';
		//dodajemy nowy handler
		$this->handlers[$handler] = array(
										 'admin' => $admin,
										 'handler' => $handler,
										 'cmd' => $cmd.((!empty($help))?' #':''),
										 'help' => $cmd.$help.' - '.$desc);
		
		//dodajemy nowy cmd
		$this->cmds[$handler][$handler] = array(
										 'type' => 0,
										 'cmd' => $cmd,
										 'desc' => $desc,
										 'ereg' => $val_ereg);
		return $handler;
	}
	private function get_cmd_table($handler) {
		$cmds = &$this->cmds;
		$h = $handler;
		$done = false;
		$handles = array($h);
		while (!$done) {
			//sprawdzamy czy handler istnieje
			if (isset($this->handlers[$h])) {
				//zapamietujemy stary
				$old = $h;
				//ustawiamy nadrzedny jako nowy
				$h = $this->handlers[$h]['handler'];
				//jezeli sa jednakowe to nie dodajemy do tablicy
				if ($h !== $old) $handles[] = $h;
				//jezeli jestesmy na poziomie zerowym to konczymy
				else $done =true;
				//pozbywamy sie zmiennej
				unset($old);
			} else {
				//blad o nieznalezionym handlerze
				$this->debug('Unknown handler ('.$h.')', DBG_WARN, 2);
				return false;
			}
			
		}
		return array_reverse($handles);
	}
	public function addSubcommand($handler, $ereg, $desc, $val_ereg=null, $admin=false) {
		//tworzymy nowy handler
		$new_handler = count($this->handlers);
		//ustawaimy adres do cmds
		$cmds = &$this->cmds;
		//sprawdzamy co zwraca funkcja generujaca zagniezdzenie
		if (!is_array($handles = $this->get_cmd_table($handler))) return false;
		//przesuwamy sie w zagniezdzeniach
		foreach($handles as $v)
			$cmds = &$cmds[$v];
		//ustawiamy ladny regexp dla wywolania pomocy
		$help = ((isset($val_ereg)&& $val_ereg!=='.+' && $val_ereg !== '.*')?' '.$val_ereg:'');
		//Jezeli jest jakis var_ereg to musi on byc ciagly
		if ($val_ereg !== null) $val_ereg = '^'.$val_ereg.'$';
		//dodajemy nowy handler
		$this->handlers[$new_handler] = array(
								'admin' => $admin,
								'handler' => $handler,
								'cmd_ereg' => $ereg,
								'cmd' => $this->handlers[$handler]['cmd'].' '.(is_array($ereg)?'%_SWITCH_%':$ereg).((!empty($help))?' #':''),
								'help' => $this->handlers[$handler]['cmd'].' '.(is_array($ereg)?'%_SWITCH_%':$ereg).$help.' - '.$desc);
		//dodajemy nowego commanda
		if (is_array($ereg)) foreach ($ereg as $k=>$v) $ereg[$k] = '^'.$v.'$';
		$cmds[$new_handler][$new_handler] = $cmds[$new_handler] = array(
								'type' => 0,
								'cmd' => ((is_array($ereg))?$ereg:'^'.$ereg.'$'),
								'desc' => $desc,
								'ereg' => $val_ereg);
		return $new_handler;
	}
	
	public function addSwitch($handler, $name, $desc, $ereg=null, $admin=false) {
		$new_handler = count($this->handlers);
		$cmds = &$this->cmds;
		if (!is_array($handles = $this->get_cmd_table($handler))) return false;
		foreach($handles as $v)
			$cmds = &$cmds[$v];
		
		if (!is_array($name)) $name = array($name);

		$this->handlers[$new_handler] = array(
											'admin' => $admin,
											'handler' => $handler,
											'cmd' => $name,
											'help'=> $this->handlers[$handler]['cmd'].' %_SWITCH_% # - '.$desc);
		$cmds[$new_handler] = array(
											'type' => 1,
											'cmd' => $name,
											'desc' => $desc, 
											'ereg' => $ereg);
		return $new_handler; 
	}
	public function help_generator_cmd($cmd) {
		$this->help = $cmd;
	}	
	public function generate_help($handler) {
		if (!isset($this->gen_help[$handler])) {
			$tablica = $this->cmds;
			$found = false;
			$i = 0;
			$send = array();
			$lang_clear = array();
			foreach($this->handlers as $k => $v) {
				if ($k == $handler) {
					foreach ($this->handlers as $a => $b) {
						if (($b['handler'] == $handler) && ($this->allow($a)) ){// && $b['handler'] !== $a) 
							$regs = array();
							$lang = $b['help'];
							if (ereg('_lang_([^ ]+)', $b['help'], $regs)) {
								$b['help'] = str_replace($regs[0], $this->bot->lang->text($regs[1]), $b['help']);
							}
							if (is_array($b['cmd']) || (isset($b['cmd_ereg']) && is_array($b['cmd_ereg']))) {
								$h='';
								$tab = ((isset($b['cmd_ereg']))?$b['cmd_ereg']:$b['cmd']);
								foreach ($tab as $x) {
									$h .= $x.' | ';
								}
								unset($tab);
								$lang_clear[] = str_replace('%_SWITCH_%', substr($h,0,strlen($h)-3), $lang);
								$send[] = str_replace('%_SWITCH_%', substr($h,0,strlen($h)-3), $b['help']);
							} elseif ($b['cmd'] !== '.*' && $b['cmd'] !== '.+'){
								$lang_clear[] = $lang;
								$send[] = $b['help'];
							}
						}
					}
					if (!count($send) && ereg(str_replace(array('%_SWITCH_%', '#'), '', $v['cmd']), $this->data_temp->message) && $this->allow($k)) {
						$tab = ((isset($v['cmd_ereg']))?$v['cmd_ereg']:$v['cmd']);
						$h='';
						if (is_array($tab))
							foreach ($tab as $x) {
								$h .= $x.' | ';
							}
						unset($tab);
						$v['help'] = str_replace('%_SWITCH_%', substr($h,0,strlen($h)-3), $v['help']);
						$lang_clear[] = $v['help'];
						$regs = array();
						if (ereg('_lang_([^ ]+)', $v['help'], $regs)) {
							$v['help'] = str_replace($regs[0], $this->bot->lang->text($regs[1]), $v['help']);
						}
						$send[] = $v['help'];
					}
					break;
				}
			}
			$this->gen_help[$handler] = $lang_clear;
			$this->debug('Generating help', DBG_INFO, 2);
		} else {
			$send = $this->gen_help[$handler];
			foreach ($send as $k=>$v) {
				$regs = array();
				if (ereg('_lang_([^ ]+)', $v, $regs)) {
					$send[$k] = str_replace($regs[0], $this->bot->lang->text($regs[1]), $v);
				}
			}
		}
		$this->bot->sendarray($send, $this->data_temp);
		return true;
	}
	private function allow($k) {
		if (!isset($this->handlers[$k])) return false; 
		if ($this->handlers[$k]['admin']) {
			return $this->bot->is_admin($this->data_temp->nick, $this->data_temp);
		}
		return true;
	}
	private function msg($lvl) {
		$msg = '';
		$ile = count($this->data_temp->messageex);
		for($i=$lvl; $i<$ile; $i++) {
			$msg .= ' '.$this->data_temp->messageex[$i];	
		}
		return trim($msg);
	}
	private function check(&$lvl, $handler=null, &$handler_array) {
		$d = &$this->data_temp->messageex;
		$ile = count($d);
		$cmds = &$this->cmds;
		$handles = (($handler !== null)?$this->get_cmd_table($handler):array());
		foreach($handles as $v)
			$cmds = &$cmds[$v];
			
		if ($d[$ile-1] == $this->help) {
			for($i=$ile-1; $i>0; $i--) {
				foreach ($this->handlers as $k=>$x) {
					if (!is_array($x['cmd'])) $x['cmd'] = array($x['cmd']);
					foreach ($x['cmd'] as $blabla) {
						$cmd = explode(' ', $blabla);
						if ($cmd[$a = (count($cmd)-1)] == '#') $a--;
						if ($cmd[$a] == $d[$i]) {
							$this->generate_help($k);
							return true;
						} elseif ($cmd[$a] === '%_SWITCH_%') {
							foreach ($x['cmd_ereg'] as $v) {
								if ($v == $d[$i]) {
									$this->generate_help($k);
									return true;
								}
							}
						}
					}
				}
			}
		}
		$tablica = array();
		foreach ($cmds as $k=>$v) {
			$tablica[]=$k;
		}
		$ile_powt = count($tablica);
		while($lvl<$ile) {
			$c = 0;
			for($ic=0;$ic<$ile_powt;$ic++) {
				$k = $tablica[$ic];
				$v = $cmds[$k];
				$c++;
				if (isset($d[$lvl]) && $this->allow($k) && is_array($v)) {
					$regs = array();
		//			var_dump($d[$lvl]);
					//var_dump($v);
					if ($lvl == 0) {
						if ($d[$lvl] == $v[$k]['cmd']) {
							$ok = true;
							$this->reparse_data($data);
							if (!isset($d[$lvl+1]) || (isset($d[$lvl+1]) && $d[$lvl+1] == $this->help)) {
								$this->generate_help($k);
								return true;
							}
							$msg = $this->msg($lvl+1);
							//sprawdzamy regexpa	
							if (isset($d[$lvl+1]) && $v[$k]['ereg'] !== null && (ereg($v[$k]['ereg'], $msg, $regs) || ereg($v[$k]['ereg'], $d[$lvl+1], $regs))) {
								$lvl++;
								$handler_array[$k] = $regs;
							} elseif($v[$k]['ereg'] !== null) {
								//syntax error
								return false;
							}
							$lvl++;
							$c = 0;
							if (!$this->check($lvl, $k, $handler_array)) return false;
						}
					} else {
						if (isset($v['cmd']) && !is_array($v['cmd'])) $v['cmd'] = array($v['cmd']);
						if (isset($v['cmd']))
							foreach ($v['cmd'] as $b) {
								if (isset($d[$lvl])) {
									if ($v['type'] && $v['ereg'] === null) {
										if (ereg($b, $d[$lvl], $regs)) {
												$handler_array[$k]=((count($regs) === 1)?true:$regs);
												$lvl++;
												$c = 0;
												$ic = -1;
												if (!$v['type'])
													if (!$this->check($lvl, $k, $handler_array)) return false;
										}
									} elseif ($v['type'] & ereg($b.'('.$v['ereg'].')', $d[$lvl], $regs)) {
										$ile_regs = count($regs);
										for ($i=1; $i<$ile_regs; $i++) {
											$regs[$i-1] = $regs[$i];
										}
										if ($ile_regs>1)
											unset($regs[$ile_regs-1]);
										$handler_array[$k] = $regs;
										$lvl++;
										$c = 0;
										$ic = -1;
									} elseif (ereg($b, $d[$lvl], $regs) && $v['ereg'] !== null) {
										//debug($d[$lvl]);
										$msg = $this->msg($lvl+1);
										//debug($msg);
										if (ereg($v['ereg'], $msg, $regs) || (isset($d[$lvl+1]) && ereg($v['ereg'], $d[$lvl+1], $regs))) {
											$handler_array[$k] = $regs;
											$lvl++;
											if (!$v['type'])
												if (!$this->check($lvl, $k, $handler_array)) return false;
										} else {
											//syntax error
											return false;
										}
									} elseif (ereg($b, $d[$lvl], $regs)) {
										$handler_array[$k] = $regs;
										$lvl++;
										$c = 0;
										$ic = -1;
										if (!$v['type'])
											if (!$this->check($lvl, $k, $handler_array)) return false;
									}
								}
						}
					}
				}
			}
			if ($c == count($cmds)) {
				$lvl++;
				if (!isset($ok)) return true;
			}
			
		}	
		return true;
	}
	
	//Zamienia data->messageex na cos bardziej przyjaznego (obslugujacego nieprzewane wyrazenia jesli sa w "")
	public function reparse_data(&$data = null) {
		if ($data == null) $data = $this->data_temp;
		$new_data = array();
		$inside = false;
		$ins = '';
		foreach ($data->messageex as $k=>$v) {
			if ($inside && substr($v, strlen($v)-1) == '"' && (substr($v, strlen($v)-2, 1) !== '\\')) {
				$inside = false;
				$ins .= ' '.substr($v, 0, strlen($v)-1);
				$new_data[] = stripslashes($ins);
				$ins = '';
			} elseif ($inside) {
				$ins .= ' '.$v;
			} elseif (substr($v,0,1) == '"') {
				$inside = true;
				$ins = substr($v, 1);	
			} else {
				$new_data[] = $v;
			}
		}
		$data->messageeex = $new_data;
		return true;
	}
	public function parse(&$data = null) {
		if ($data == null) $data = $this->data_temp;
		$handler_array = array();
		if (isset($data->message) && count($this->handlers)) {
			$lvl = 0;
			if (!$this->check($lvl, null, $handler_array)) {
				$this->debug('Command syntax error', DBG_INFO, 2);
				$this->bot->send_text('wrong_syntax', 0, $this->data_temp);
				return false;
			}
		}
		return $handler_array;
	}
	public function data($data) {
		if ($data !== null) {
			$this->data_temp = &$data;
			if ($this->autoparse) {
				return $this->parse();
			}
		} else {
			$this->data_temp = null;
			return 0;
		}
	}	
	public function __destruct() {
		$this->data_temp = null;
		$this->exec_module = null;/*
		print_r($this->switches);
		print_r($this->cmds);
		print_r($this->handlers);*/
	}
}
?>